#include "map_utils.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "net_defs.h"

#define MAP_CAPACTIY 1 << 16

#define KEY_MAX 256
#define VALUE_MAX 256

uint32_t str_hash(void* key)
{
    return time33(key);
}

int str_equal_f(void* k1, void* k2)
{
    return (0 == strcmp((char*)k1, (char*)k2));
}

// int str_equal_f(void* k1, void* k2)
// {
//     return (0 == memcmp(k1, k2, STR_KEY_MAX_LEN));
// }

uint32_t int_hash(void* key)
{
    return dict_int_hash(*((uint32_t*)key));
}

int int_equal_f(void* k1, void* k2)
{
    return *((uint32_t*)k1) == *((uint32_t*)k2);
}

int map_put_str(hash_map* map, const char* key, uint32_t value)
{
    if (!map || !key || !strlen(key)) {
        // printf("%s: invalid args!\n", __FUNCTION__);
        return -1;
    }

    map_entry* tmp = (map_entry*)malloc(sizeof(map_entry));
    memset(tmp, 0, sizeof(map_entry));
    tmp->key = strdup(key);
    tmp->val = malloc(sizeof(uint32_t));
    memset(tmp->val, 0, sizeof(uint32_t));
    uint32_t* v = (uint32_t*)tmp->val;
    *v = value;
    return map_put(map, tmp);
}

int map_put_int(hash_map* map, uint32_t key, uint32_t value)
{
    if (!map || value < 1) {
        // printf("%s: invalid args!\n", __FUNCTION__);
        return -1;
    }
    map_entry* tmp = (map_entry*)malloc(sizeof(map_entry));
    memset(tmp, 0, sizeof(map_entry));
    tmp->key = malloc(sizeof(uint32_t));
    memset(tmp->key, 0, sizeof(uint32_t));
    int* k = (int*)tmp->key;
    *k = key;

    tmp->val = malloc(sizeof(uint32_t));
    memset(tmp->val, 0, sizeof(uint32_t));
    uint32_t* v = (uint32_t*)tmp->val;
    *v = value;
    return map_put(map, tmp);
}

int map_put_int_xor(hash_map* map, uint32_t xkey, uint32_t xval)
{
    if (!map) {
        printf("%s: invalid args\n", __FUNCTION__);
        return -1;
    }
    map_entry* e = map_get(map, &xkey);
    if (e) {
        uint32_t key = *(uint32_t*)(e->key);
        uint32_t val = *(uint32_t*)(e->val);
        // printf("key exist: %d -> val: %d\n", key, val);

        xval |= val;
    }
    return map_put_int(map, xkey, xval);
}

void map_int_xor_for_each(hash_map* map, uint32_t xval)
{
    map_entry* e = NULL;
    map_for_each(map, e)
    {
        uint32_t key = *(uint32_t*)e->key;
        uint32_t val = *(uint32_t*)e->val;
        // printf("map_int_xor_for_each key:%d -> val:%d\n", key, val);
        map_put_int_xor(map, key, xval);
    }
}

int map_put_str_xor(hash_map* map, char* xkey, uint32_t xval)
{
    if (!map || !xkey || !strlen(xkey)) {
        printf("%s: invalid args\n", __FUNCTION__);
        return -1;
    }
    map_entry* e = map_get(map, xkey);
    if (e) {
        char* key = (char*)(e->key);
        uint32_t val = *(uint32_t*)(e->val);
        // printf("str key exist: %s -> val: %d\n", key, val);

        xval |= val;
    }
    return map_put_str(map, xkey, xval);
}

void map_str_xor_for_each(hash_map* map, uint32_t xval)
{
    map_entry* e = NULL;
    map_for_each(map, e)
    {
        char* key = (char*)e->key;
        int val = *(int*)e->val;
        // printf("map_str_xor_for_each key:%s -> val:%d\n", key, val);
        map_put_str_xor(map, key, xval);
    }
}

int load_str_map(hash_map* map, const char* cfg_file)
{
    if (!map || !cfg_file) {
        printf("invalid args !\n");
        return -1;
    }

    FILE* fp = fopen(cfg_file, "r");
    if (!fp) {
        perror("fopen");
        return -1;
    }

    char buff[LINE_MAX];
    char key_buf[KEY_MAX];
    char val_buf[VALUE_MAX];

    while (!feof(fp)) {
        bzero(buff, LINE_MAX);
        bzero(key_buf, KEY_MAX);
        bzero(val_buf, VALUE_MAX);
        fgets(buff, LINE_MAX, fp);

        sscanf(buff, "%s %s\n", key_buf, val_buf);
        map_put_str(map, key_buf, atoi(val_buf));
    }

    fclose(fp);
    return EXIT_SUCCESS;
}

int save_str_map(hash_map* map, const char* cfg_file)
{
    if (!map || !cfg_file) {
        printf("invalid args !\n");
        return -1;
    }

    FILE* fp = fopen(cfg_file, "w");
    if (!fp) {
        perror("fopen");
        return -1;
    }

    char buff[LINE_MAX];
    map_entry* e = NULL;
    map_for_each(map, e)
    {
        char* key = (char*)e->key;
        uint32_t val = *(uint32_t*)e->val;
        if (strlen(key) < 1)
            continue;
        // printf("save key:%s -> val:%d\n", key, val);
        bzero(buff, LINE_MAX);
        snprintf(buff, LINE_MAX - 1, "%s %d\n", key, val);
        fputs(buff, fp);
    }

    fclose(fp);

    return EXIT_SUCCESS;
}

int load_int_map(hash_map* map, const char* cfg_file)
{
    if (!map || !cfg_file) {
        printf("invalid args !\n");
        return -1;
    }

    FILE* fp = fopen(cfg_file, "r");
    if (!fp) {
        perror("fopen");
        return -1;
    }

    char buff[LINE_MAX];
    char key_buf[KEY_MAX];
    char val_buf[VALUE_MAX];

    while (!feof(fp)) {
        bzero(buff, LINE_MAX);
        bzero(key_buf, KEY_MAX);
        bzero(val_buf, VALUE_MAX);
        fgets(buff, LINE_MAX, fp);

        int len = strlen(buff);
        if (len > 0 && '\n' == buff[len - 1]) {
            buff[len - 1] = '\0';
        }

        sscanf(buff, "%s %s", key_buf, val_buf);
        map_put_int(map, atoi(key_buf), atoi(val_buf));
    }

    fclose(fp);

    return EXIT_SUCCESS;
}

int save_int_map(hash_map* map, const char* cfg_file)
{
    if (!map || !cfg_file) {
        printf("invalid args !\n");
        return -1;
    }

    FILE* fp = fopen(cfg_file, "w");
    if (!fp) {
        perror("fopen");
        return -1;
    }

    char buff[LINE_MAX];
    map_entry* e = NULL;
    map_for_each(map, e)
    {
        uint32_t key = *(uint32_t*)e->key;
        uint32_t val = *(uint32_t*)e->val;
        if (val < 1)
            continue;
        // printf("save key:%d -> val:%d\n", key, val);
        bzero(buff, LINE_MAX);
        snprintf(buff, LINE_MAX - 1, "%d %d\n", key, val);
        fputs(buff, fp);
    }

    fclose(fp);

    return EXIT_SUCCESS;
}

void print_str_map(hash_map* map, const char* reason)
{
    printf("%s:\n", reason);
    map_entry* e = NULL;
    map_for_each(map, e)
    {
        if (e)
            printf("\tkey:%s -> val:%d\n", (char*)e->key, *(int*)e->val);
    }
}

void print_int_map(hash_map* map, const char* reason)
{
    printf("%s:\n", reason);
    map_entry* e = NULL;
    map_for_each(map, e)
    {
        if (e)
            printf("\tkey:%d -> val:%d\n", *(int*)e->key, *(int*)e->val);
    }
}